using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using Common.Utilities;
using Common.Utilities.Dispatcher;
using Workflows.Components.Properties;

namespace Workflows.Components
{
    /// <summary></summary>
    [Serializable]
    public class Subflow:WorkflowComponentBase
    {
        #region props
        private SubflowInstruction _Instruction;
        private SubflowOutput _Output;

        public override InstructionBase Instruction
        {
            get { return _Instruction; }
            set { _Instruction =(SubflowInstruction) value; }
        }

        public override ResultBase Output
        {
            get { return _Output; }
            set { _Output =(SubflowOutput) value; }
        }

        /// <summary></summary>
        public Guid SubFlowID
        {
            get { return this._Instruction.SubFlowID; }
            set { this._Instruction.SubFlowID = value; }
        }

        /// <summary></summary>
        public List<string> LoopableData
        {
            get { return this._Instruction.LoopableData; }
            set { this._Instruction.LoopableData = value; }
        }

        /// <summary></summary>
        public string IteratorDataName
        {
            get { return this._Instruction.IteratorDataName; }
            set { this._Instruction.IteratorDataName = value; }
        }

        /// <summary></summary>
        public string IteratorDataCollectionName
        {
            get { return this._Instruction.IteratorDataCollectionName; }
            set { this._Instruction.IteratorDataCollectionName = value; }
        }

        /// <summary></summary>
        public int CurrentInputIndex
        {
            get { return this._Instruction.CurrentInputIndex; }
            set { this._Instruction.CurrentInputIndex = value; }
        }

        /// <summary></summary>
        public Type InstructionItemType
        {
            get
            {
                return this._Instruction.InstructionItemType;
            }
            set
            {
                this._Instruction.InstructionItemType = value;
            }
        }

        //public List<GlobalVariable> SubflowGlobalVariables
        //{
        //    get
        //    {
        //        return this._Instruction.SubflowGlobalVariables;
        //    }
        //    set
        //    {
        //        this._Instruction.SubflowGlobalVariables = value;
        //    }
        //}

        #endregion
        /// <summary></summary>
        public Subflow():base()
        {
            this.ComponentName = "Subflow";
            this.Description = "Call another workflow";
            this.ComponentIcon = Resources.MessageQueuing;
            this.ComponentImage = Resources.programok;
            this.ComponentActivityType = WorkflowActivityType.SimpleActivity;
            this.ComponentCategory = WorkflowComponentCategory.External_Processes.ToString();

            this._Instruction =
                new SubflowInstruction(this.ComponentID, Guid.Empty, Guid.Empty, Type.Missing.GetType(), null,
                                       string.Empty, string.Empty, -1);
            this._Output = new SubflowOutput(this.ComponentID, Guid.Empty, 0, 0, null);
        }

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = base.Serialize(ref xDoc, ref parentNode);

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubflowID", this.SubFlowID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "InstructionItemType", this.InstructionItemType.FullName);

            // XmlNode instructionRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "SubflowInstructionCollection");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CurrentIndex",this.CurrentInputIndex.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IteratorDataName", this.IteratorDataName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "IteratorDataCollectionName", this.IteratorDataCollectionName);

            //if (this.InputCollection != null && this.InputCollection.Count > 0)
            //{
            //    for (int i = 0; i < this.InputCollection.Count; i++)
            //    {
            //        this.InputCollection[i].Serialize(ref xDoc, ref instructionRootNode);
            //    }
            //}

            //XmlNode subflowGlobalVarRootNode = XmlDataUtil.AddElement(ref xDoc, xNode, "SubflowGlobalVariables");
            //if (this.SubflowGlobalVariables != null && this.SubflowGlobalVariables.Count > 0)
            //{
            //    foreach (GlobalVariable var in this.SubflowGlobalVariables)
            //    {
            //        XmlNode varNode = XmlDataUtil.AddElement(ref xDoc, subflowGlobalVarRootNode, "Variable");
            //        XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "VariableName", var.VarName);
            //        XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "DataType", ((int) var.DataType).ToString());
            //        XmlDataUtil.UpdateAttribute(ref xDoc, varNode, "VariableValue", var.VarValue.ToString());
            //    }
            //}

            return xNode;
        }

        public override WorkflowComponentBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                Subflow component = base.Instantiate(xNode) as Subflow;

                component.SubFlowID = new Guid(xNode.Attributes.GetNamedItem("SubflowID").Value);
                string instructItemTypeName = xNode.Attributes.GetNamedItem("InstructionItemType").Value;
                string binFolderPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
                DirectoryInfo dirInfo = new DirectoryInfo(binFolderPath);
                FileInfo[] dllInfos = dirInfo.GetFiles("*.dll", SearchOption.TopDirectoryOnly);
                foreach (FileInfo dllInfo in dllInfos)
                {
                    try
                    {
                        Assembly assem = Assembly.LoadFile(dllInfo.FullName);
                        Type type = assem.GetType(instructItemTypeName);
                        if (type != null)
                        {
                            component.InstructionItemType = type;
                            break;
                        }
                    }
                    catch
                    {
                        Console.WriteLine("");
                    }
                }
                component.CurrentInputIndex = int.Parse(xNode.Attributes.GetNamedItem("CurrentIndex").Value);
                component.IteratorDataName = xNode.Attributes.GetNamedItem("IteratorDataName").Value;
                component.IteratorDataCollectionName =
                    xNode.Attributes.GetNamedItem("IteratorDataCollectionName").Value;


                //XmlNode subflowInstructionRootNode = xNode.SelectSingleNode("//SubflowInstructionCollection");
                //if (subflowInstructionRootNode != null)
                //{
                //    component.CurrentInputIndex =
                //        int.Parse(subflowInstructionRootNode.Attributes.GetNamedItem("CurrentIndex").Value);
                //    component.InputCollection = null;
                //    if (subflowInstructionRootNode.ChildNodes != null && subflowInstructionRootNode.ChildNodes.Count > 0 &&
                //        component.InstructionItemType != null && component.InstructionItemType != Type.Missing.GetType())
                //    {
                //        component.InputCollection = new List<InstructionBase>();
                //        foreach (XmlNode subflowInstructNode in subflowInstructionRootNode.ChildNodes)
                //        {
                //            InstructionBase subflowInstruction =
                //                (InstructionBase)Activator.CreateInstance(component.InstructionItemType);
                //            subflowInstruction = subflowInstruction.Instantiate(subflowInstructNode);
                //            component.InputCollection.Add(subflowInstruction);
                //        }
                //    }
                //}

                //component.SubflowGlobalVariables = null;
                //XmlNodeList wfVarNodes = xNode.SelectNodes("SubflowGlobalVariables/Variable");
                //if (wfVarNodes != null && wfVarNodes.Count > 0)
                //{
                //    component.SubflowGlobalVariables = new List<GlobalVariable>();
                //    foreach (XmlNode varNode in wfVarNodes)
                //    {
                //        GlobalVariable wfVar = new GlobalVariable();
                //        wfVar.VarName = varNode.Attributes.GetNamedItem("VariableName").Value;
                //        wfVar.DataType =
                //            (SimpleDataType) int.Parse(varNode.Attributes.GetNamedItem("DataType").Value);
                //        wfVar.VarValue = SimpleDataTypeConverter.ConvertFrom(varNode.Attributes.GetNamedItem("VariableValue").Value, wfVar.DataType).ToString();
                //        component.SubflowGlobalVariables.Add(wfVar);
                //    }
                //}

                return component;
            }
            else
            {
                throw new Exception("Unable to instantiate component: invalid type specified in xml node");
            }
        }
    }
}
